package com.anolesoft.yr.mbus.contm.util;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.anolesoft.yr.mbus.contm.entity.*;
import com.google.common.collect.Lists;
import org.dom4j.*;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipInputStream;

public class DocUtil {
    /**
     * 更改标题内容
     *
     * @param xmlText
     * @param aimText
     * @return
     * @throws DocumentException
     */
    public static Element changeTitleText(String xmlText, String aimText) throws DocumentException {
        Document document = DocumentHelper.parseText(xmlText);
        Element element = document.getRootElement();
        List<Element> elements = element.elements("r");
        int a = 0;
        if (elements.size() > 0) {
            while (elements.get(a).elements("t").size() <= 0) {
                a++;
            }
            for (int i = 1 + a; i < elements.size(); i++) {
                element.remove(elements.get(i));
            }
        }
        Element rElement = element.elements("r").get(a);
        rElement.element("t").setText(aimText);
        return element;
    }
    public static Element changeTitleText(Element element, String aimText) throws DocumentException {
        List<Element> elements = element.elements("r");
        int a = 0;
        if (elements.size() > 0) {
            while (elements.get(a).elements("t").size() <= 0) {
                a++;
            }
            for (int i = 1 + a; i < elements.size(); i++) {
                element.remove(elements.get(i));
            }
        }
        Element rElement = element.elements("r").get(a);
        rElement.element("t").setText(aimText);
        return element;
    }


    /**
     * 生成表格方法
     *
     * @param xmlText
     * @param lst
     * @return
     * @throws DocumentException
     */
    public Element changeTable(String xmlText, List<List<String>> lst) throws DocumentException {
        Document document = DocumentHelper.parseText(xmlText);
        Element element = document.getRootElement();

        List<Element> elements = element.elements("tr");

        for (int i = 0; i < elements.size(); i++) {
            List<Element> tcElements = elements.get(i).elements("tc");
            for (int j = 0; j < tcElements.size(); j++) {
                List<Element> tcPElements = tcElements.get(j).elements("p");
                for (int k = 1; k < tcPElements.size(); k++) {
                    tcElements.remove(tcPElements.get(k));
                }
            }
        }
        for (int i = 0; i < elements.size(); i++) {
            List<Element> tcElements = elements.get(i).elements("tc");
            for (int j = 0; j < tcElements.size(); j++) {
                Element tcPElement = tcElements.get(j).element("p");
                List<Element> tcPRElements = tcPElement.elements("r");
                for (int k = 1; k < tcPRElements.size(); k++) {
                    tcPRElements.remove(tcPRElements.get(k));
                }
            }
        }


        if (elements.size() < 2) {
            throw new RuntimeException("缺少表头或表内容格式信息");
        }
        for (int i = 0; i < lst.size(); i++) {
            //如果存在样式相同的行这直接用相同的行
            if (elements.size() >= i) {
                if (elements.get(i).elements("tc").size() >= lst.get(i).size()) {
                    List<String> row = lst.get(i);
                    for (int j = 0; j < row.size(); j++) {
                        elements.get(i).elements("tc").get(j).element("p").element("r").element("t").setText(row.get(j));
                    }
                }
                //隔行换色情况
            } else if (elements.size() < i && elements.size() >= 3) {
                Element trElement = elements.get(i % 2 + 2);
                if (trElement.elements("tc").size() >= lst.get(i).size()) {
                    List<String> row = lst.get(i);
                    for (int j = 0; j < row.size(); j++) {
                        trElement.elements("tc").get(j).element("p").element("r").element("t").setText(row.get(j));
                    }
                }
                elements.add(trElement);
            }
        }
        return element;
    }


    private Map<String, AbstractNum> getNumberingDocumnet(File documentFile) throws IOException, DocumentException {
        String xmlName = "word/numbering.xml";
        Map<String, AbstractNum> map = new HashMap<String, AbstractNum>();
        //获取document.xml
        Element documentElement = getXmlFile(documentFile, xmlName).get(xmlName);
        List<Element> abstractNumsXmlList = documentElement.elements("abstractNum");
        Map<String, AbstractNum> abstractNumMap = new HashMap<>();
        List<Element> numList = documentElement.elements("num");
        abstractNumsXmlList.stream().forEach(abstractNum -> {
            String abstractNumId = abstractNum.attributeValue("abstractNumId");
            String key = "-1";
            List<Lvl> lst = new ArrayList<>();
            for (int i = 0; i < numList.size(); i++) {

                String tempAbId = numList.get(i).element("abstractNumId").attributeValue("val");
                if (abstractNumId.equals(tempAbId)) {
                    key = abstractNum.attributeValue("numId");
                    List<Element> lvlList = abstractNum.elements("lvl");
                    lvlList.forEach(a -> {
                        String start = a.element("start").attributeValue("val");
                        String lvlText = a.element("lvlText").attributeValue("val");
                        String iviId = a.attributeValue("lvl");
                        Lvl lvl = new Lvl(start, lvlText, iviId);
                        lst.add(lvl);
                    });
                }
            }

            if (key != null && !"".equals(key)) {
                AbstractNum abstractNumTemp = new AbstractNum();
                abstractNumTemp.setAbstractNumId(Integer.parseInt(abstractNumId));
                abstractNumTemp.setNumId(Integer.parseInt(key));
                ;
                abstractNumTemp.setLvls(lst);
                map.put(key, abstractNumTemp);
            }
        });
        return map;
    }

    /**
     * 获取样式文档
     *
     * @param documentFile
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public Map<String, Style> getStyleDocument(File documentFile) throws IOException, DocumentException {
        String xmlName = "word/styles.xml";
        Map<String, Style> map = new HashMap<String, Style>();
        Element documentElement = getXmlFile(documentFile, xmlName).get(xmlName);
        List<Element> styleXmlList = documentElement.elements("style");
      /*  styleXmlList = styleXmlList.stream().filter(element ->
                "paragraph".equals(element.attributeValue("type"))
        ).collect(Collectors.toList());*/
        styleXmlList.stream().forEach(s -> {
            if (s.element("pPr") != null && s.element("pPr").element("numPr") != null) {
                String ilvl = s.element("pPr").element("numPr").element("ilvl") == null ? "0" : s.element("pPr").element("numPr").element("ilvl").attributeValue("val");
                String numId = s.element("pPr").element("numPr").element("numId").attributeValue("val");
                String styleId = s.attributeValue("styleId");
                Style style = new Style(styleId, ilvl, numId);
                map.put(styleId, style);
            } else {
                // String ilvl = s.element("pPr").element("numPr").attributeValue("ilvl") == null ? "0" : s.element("pPr").element("numPr").attributeValue("ilvl");
                //  String numId = s.element("pPr").element("numPr").attributeValue("numId");
                String styleId = s.attributeValue("styleId");
                Style style = new Style(styleId, "", "");
                map.put(styleId, style);
            }
        });

        return map;

    }

    /**
     * 从zip文件中获取xml文件数据
     *
     * @param zipFile
     * @param xmlName
     * @return
     * @throws IOException
     * @throws DocumentException
     */
    public static Map<String, Element> getXmlFile(File zipFile, String xmlName) throws IOException, DocumentException {
        Map<String, Element> map = new HashMap<String, Element>();

        String path = zipFile.getParent() + File.separator + zipFile.getName();
        ZipFile zf = new ZipFile(path);
        SAXReader reader = new SAXReader();
        InputStream in = new BufferedInputStream(new FileInputStream(path));
        Charset gbk = Charset.forName("gbk");
        ZipInputStream zin = new ZipInputStream(in, gbk);
        ZipEntry ze;
        while ((ze = zin.getNextEntry()) != null) {
            if (ze.toString().startsWith(new String(xmlName.getBytes("utf-8"), "gbk"))) {

                Document document = reader.read(zf.getInputStream(ze));//读取xml文档
                Element root = document.getRootElement();
                map.put(ze.toString(), root);

            }
        }
        zin.closeEntry();
        return map;
    }


    /**
     * 获取段落文字 解决文字里的特殊内容
     *
     * @param element docx文件的P节点
     * @return
     */
    public static String getPText(Element element) {
        return element.getStringValue().trim().replaceAll(" *", "").replaceAll("\r|\n|\\s", "");
    }

    /**
     * 处理wordxml代码中有多个r的问题
     *
     * @param element docx文件的P节点
     * @return 干净的code内容，只存在一个r属性
     */
    public static String formatStyleCode(Element element) {
        List<Element> rElements = element.elements("r");
        if (rElements != null && rElements.size() > 1) {
            for (int i = 1; i < rElements.size(); i++) {
                element.remove(rElements.get(i));
            }
        }
        return element.asXML();
    }

    /**
     * 获取字体样式，如果没找到给一个默认的宋体
     *
     * @param element docx文件的P节点
     * @return
     */
    public static String getFont(Element element) {
        Element pPr = element.element("pPr");
        if (pPr != null) {
            Element rPr = pPr.element("rPr");
            return rPr.element("rFonts").attributeValue("eastAsia");
        } else {
            return "宋体";
        }

    }

    /**
     * 获取对齐方式，如果没找到默认左对齐
     *
     * @param element docx文件的P节点
     * @return
     */
    public static String getJc(Element element) {
        Element pPr = element.element("pPr");
        if (pPr != null) {
            Element jc = pPr.element("jc");
            if (jc != null) {
                return jc.attributeValue("val");
            } else {
                return "left";
            }
        } else {
            return "left";
        }
    }

    /**
     * 设置段落对齐方式
     *
     * @param element docx文件的P节点
     * @param jc
     */
    public static void setJc(Element element, String jc) {
        Element jcElement = element.element("pPr").element("jc");
        if (jc != null) {
            Attribute attribute = jcElement.attribute("val");
            attribute.setValue(jc);
        }
    }

    /**
     * 获取字体大小，如果没找到设置为0，反正不可能找不到，找不到那就是空字符串没有文字页无所谓
     *
     * @param element
     * @return
     */
    public static String getFontSize(Element element) {
        Element pPr = element.element("pPr");
        if (pPr != null) {
            Element rPr = pPr.element("rPr");
            return rPr.element("sz").attributeValue("val");
        } else {
            return "0";
        }
    }

    /**
     * 根据表格的样式及其表单的Json生成tbl节点。
     *
     * @param element       给定的标准tbl节点，表头一个tc，数据字段一个tc，一共两个tc
     * @param headJsonArray 给定的表头json 格式：[{column：序号，colspan：2},{...}] 注：暂时不支持colspan值设定
     * @param valueArray    给的结果json 格式[{1,2,3,4,5}] 对应上边json的数量
     * @return
     */
    public static Element formatDocTable(Element element, JSONArray headJsonArray, List<List<String>> valueArray) {
        //建立一个新的tbl
        Element copyTblElement = element.createCopy();
        List<Element> elements = copyTblElement.elements("tr");
        elements.forEach(temp -> {
            copyTblElement.remove(temp);
        });
        //建立一个新的head的tr
        Element headTrElement = element.elements("tr").get(0).createCopy();
        List<Element> tcTempElement = headTrElement.elements("tc");
        tcTempElement.forEach(temp -> {
            headTrElement.remove(temp);
        });

        Element headTcCopy = element.element("tr").element("tc").createCopy();
        //首先保证copy的element中只有一个p 而且一个p中只有一个r方便进行替换
        //1。去掉多余的p
        List<Element> ps = headTcCopy.elements("p");
        if (ps != null && ps.size() > 1) {
            for (int j = 1; j < ps.size(); j++) {
                headTcCopy.remove(ps.get(j));
            }
        }
        //2。去掉多余的r
        List<Element> rs = headTcCopy.element("p").elements("r");
        if (rs != null && rs.size() > 1) {
            for (int j = 1; j < rs.size(); j++) {
                headTcCopy.element("p").remove(rs.get(j));
            }
        }
        for (int i = 0; i < headJsonArray.size(); i++) {
            JSONObject header = headJsonArray.getJSONObject(i);
            //把文字替换好
            headTcCopy.element("p").element("r").element("t").setText(header.getString("column"));
            //放入tr中存起来
            headTrElement.add(headTcCopy.createCopy());
        }
        copyTblElement.add(headTrElement);
        //以上搞定表头，下边搞定内容

        for (int i = 0; i < valueArray.size(); i++) {
            List<String> bodyValues = valueArray.get(i);
            Element bodyTrElement = element.elements("tr").get(1).createCopy();
            Element bodyTcCopy = bodyTrElement.element("tc").createCopy();

            List<Element> bodyTcTempElement = bodyTrElement.elements("tc");
            bodyTcTempElement.forEach(temp -> {
                bodyTrElement.remove(temp);
            });


            //首先保证copy的element中只有一个p 而且一个p中只有一个r方便进行替换
            //1。去掉多余的p
            List<Element> bps = bodyTcCopy.elements("p");
            if (bps != null && bps.size() > 1) {
                for (int j = 1; j < bps.size(); j++) {
                    bodyTcCopy.remove(bps.get(j));
                }
            }
            //2。去掉多余的r
            List<Element> brs = bodyTcCopy.element("p").elements("r");
            if (brs != null && brs.size() > 1) {
                for (int j = 1; j < brs.size(); j++) {
                    bodyTcCopy.element("p").remove(brs.get(j));
                }
            }
            for (int j = 0; j < bodyValues.size(); j++) {

                String bodyTest = bodyValues.get(j);
                //把文字替换好
                bodyTcCopy.element("p").element("r").element("t").setText(bodyTest);
                //放入tr中存起来
                bodyTrElement.add(bodyTcCopy.createCopy());
            }
            copyTblElement.add(bodyTrElement);

        }
        return copyTblElement;
    }

    /**
     * @param text      目标文字
     * @param modelText
     * @return
     */
    public Element changText(String text, String modelText) {
        return null;
    }

    public static List<Row> getRText(String text) throws DocumentException {

        Element rootElement = DocumentHelper.parseText(text).getRootElement();

        List<Element> elements = new ArrayList<>();
        DocUtil.loop(rootElement,elements);
        List<Element> collect = elements.stream().distinct().collect(Collectors.toList());
        List<Row> list = new ArrayList<>();
        collect.forEach(a->{
            Row row = new Row();
            row.setContent(a.getText());
            List<String> strings = new ArrayList<>();
            DocUtil.loop2(a,strings);
            row.setStyles(strings);
            list.add(row);
        });

        return list;


      /*  List<RRoot> resultRRoots = new ArrayList<>();
        List<RRoot> temp = new ArrayList<>();

        List<RRoot> rTextByRRootText = getRTextByRRootText(text,new RRoot());
        temp.addAll(rTextByRRootText);
        for (int i = 0; i < rTextByRRootText.size(); i++) {
            RRoot rRoot = rTextByRRootText.get(i);
            List<RRoot> rTextByRRootText1 = getRTextByRRootText(rRoot.getContent(), rRoot);
            for (int i1 = 0; i1 < rTextByRRootText1.size(); i1++) {
                RRoot rRoot1 = rTextByRRootText1.get(i1);
                temp = getRTextByRRootText(rRoot1.getContent(), rRoot1);
            }
        }

        for (int i = 0; i < temp.size(); i++) {
            RRoot rRoot = temp.get(i);
            RRoot tempRoot = temp.get(i);
            while(rRoot.getParentRRoot()!=null){
                tempRoot.getStyles().add(rRoot.getStyle());
                rRoot = rRoot.getParentRRoot();
            }
            rRoot.setStyles(rRoot.getStyles().stream().collect(Collectors.toList()));
        }
        return temp;*/
    }



  /*  *//**
     * 获取P标签中的每一个Rroot节点
     *
     * @param text
     * @return
     *//*
    public static List<RRoot> getRTextByRRootText(String text, RRoot rRoot) {
        String[] split = text.split("");
        List<RRoot> roots = new ArrayList<>();
        if (text.indexOf("<") > 0 && text.length() > text.indexOf("<") + 3) {
            RRoot firstRroot = new RRoot();
            firstRroot.setStyle("n");
            List<Integer> cuts = new ArrayList<>();
            findLabel(text, cuts);
            int firstLable = cuts.stream().reduce((a, b) -> a + b).get() - 1;
            firstRroot.setContent(text.substring(0, firstLable));
            firstRroot.setParentRRoot(rRoot);
            text = text.substring(firstLable);
            roots.add(firstRroot);
        }

        if (text.indexOf("<") >= 0 && text.length() > text.indexOf("<" + 3) && text.substring(text.indexOf("<") + 2, text.indexOf("<") + 3).equals(">")) {
            textSubLoop(roots, text,rRoot);
        }
        return roots;
    }

    private static void textSubLoop(List<RRoot> roots, String text,RRoot parentRRoot) {


        if (text.indexOf("<") > 0) {
            RRoot rRoot = new RRoot();
            rRoot.setStyle("n");
            List<Integer> cuts = new ArrayList<>();
            findLabel(text, cuts);
            int index = cuts.stream().reduce((a, b) -> a + b).get() - 1;
            rRoot.setContent(text.substring(0, index + 1));
            rRoot.setParentRRoot(parentRRoot);
            roots.add(rRoot);
            text = text.substring(index);

        } else {


            String label = text.substring(text.indexOf("<") + 1, text.indexOf("<") + 2);
            String substring = text.substring(text.indexOf(">") + 1);
            String content = substring.substring(0, substring.indexOf("</" + label + ">"));
            if (substring.length() > substring.indexOf("</" + label + ">") + 1) {
                text = substring.substring(substring.indexOf("</" + label + ">") + 4);
            }
            RRoot rRoot = new RRoot();
            rRoot.setContent(content);
            rRoot.setStyle(label);
            rRoot.setParentRRoot(parentRRoot);

            roots.add(rRoot);
        }
        if (text.length() > 4) {
            List<Integer> cuts = new ArrayList<>();
            findLabel(text, cuts);
            int labelIndex = cuts.stream().reduce((a, b) -> {
                return a + b;
            }).get() - 1;
            if(labelIndex <=0 ){
                RRoot rRoot = new RRoot();
                rRoot.setContent(text);
                rRoot.setStyle("n");
                rRoot.setParentRRoot(parentRRoot);

                roots.add(rRoot);
            } else if (labelIndex > 0) {
                textSubLoop(roots, text,parentRRoot);
            }
        } else {
            RRoot rRoot = new RRoot();
            rRoot.setContent(text);
            rRoot.setStyle("n");
            rRoot.setParentRRoot(parentRRoot);
            roots.add(rRoot);
        }
    }

    *//**
     * 寻找标签位置
     *
     * @param text
     * @param cut
     *//*
    public static void findLabel(String text, List<Integer> cut) {
        String copy = text;
        int i = copy.indexOf("<");
        if ((copy.substring(i + 2, i + 3).equals(">") && copy.indexOf("</" + copy.substring(i + 1, i + 2) + ">") >= 0)||i==-1) {
            cut.add(i + 1);
        } else {
            cut.add(i + 1);
            findLabel(copy.substring(copy.indexOf("<") + 1), cut);
        }
    }
    */

    /**
     * 由于有存在一段话里边不同格式的问题，比如某一个字符斜体了 某几个字需要加上下划线了 ，就需要将存储好的文字放在不同的<w:r></>
     * 中，这样就能在自然段中就可以有不同的样式了，在V1版本中暂时就只支持BUI这几种不同的样式吧
     * @param rows
     * @param styleElement
     * @return
     */
    public static Element getPElement(List<Row> rows, Element styleElement) throws DocumentException {
        Element rStyleElement = null ;
        List<Element> r = styleElement.elements("r");
        for (int i = 0; i < r.size(); i++) {
            if (r.get(i).elements("t").size()>0){
                rStyleElement = r.get(i);
                break;
            }
        }

        Element pCopy = styleElement.createCopy();
        List<Element> tList = Lists.newArrayList();
        for (int i = 0; i < pCopy.elements("r").size(); i++) {
            if (pCopy.elements("r").get(i).elements("t").size()>0){
                tList.add(pCopy.elements("r").get(i));
            }
        }
        for (int i = 0; i < tList.size(); i++) {
            pCopy.remove(tList.get(i));
        }

        for (int i = 0; i < rows.size(); i++) {
            Row row = rows.get(i);
            Element copy = rStyleElement.createCopy();
            copy.element("t").setText(row.getContent());
            //判断有哪些特殊标记
            if(row.getStyles().contains("b")){
                copy.element("rPr").add ( DocumentHelper.createElement("w:b"));
            }
            if(row.getStyles().contains("u")){
                copy.element("rPr").add (  DocumentHelper.createElement("w:u"));
            }
            if(row.getStyles().contains("i")){
                copy.element("rPr").add (  DocumentHelper.createElement("w:i"));
            }
            pCopy.add(copy);

        }
        return pCopy;
    }



/*    public static void main(String[] args) {
  *//*      List<RRoot> rText = DocUtil.getRText("dfdfd<u><b>123232</b></u>dfsdfsdfsd");
        rText.forEach(a->{
            System.out.println(a.getContent());
        });*//*
        String xml = "<p>\n" +
                "    撒旦飞洒地方撒旦发射<strong>点发生的方式<em>发士大夫省的范德萨方式的方式说的</em></strong><span style=\"text-decoration: underline;\"><strong><em>都是 都是</em></strong><em>发射点</em><strong><em>犯得上发生的</em></strong></span><br/>\n" +
                "</p>";
        try {
            Element rootElement = DocumentHelper.parseText(xml).getRootElement();
            ArrayList<Element> elements = new ArrayList<>();
            DocUtil.loop(rootElement,elements);
            List<Element> collect = elements.stream().distinct().collect(Collectors.toList());
            for (int i = 0; i < collect.size(); i++) {
             // DocUtil.loop2(collect.get(i));
            }

        }catch (Exception e){
            e.printStackTrace();
        }
    }*/


    public static void loop(Element element,List<Element> list){
        List<Element> elements = element.elements();
        if(!"".equals(element.getText())){
            list.add(element);
        }
        if (elements.size()==0){
            list.add(element);
        }else{
            for (int i = 0; i < elements.size(); i++) {
                if (elements.get(i).getText()!="") {
                    list.add(elements.get(i));
                }
                loop(elements.get(i),list);
            }
        }
    }

    public static void loop2(Element element,List<String> tagList){
        Element temp = element;
        while(temp.getParent()!=null){
            tagList.add(temp.getName());
            temp = temp.getParent();
        }
    }
    public static List<String> titleTypes(){
        List<String> titleTypes = new ArrayList<>();
        titleTypes.add("sy_bt");
        titleTypes.add("fy_bt");
        titleTypes.add("fy_djbt");
        titleTypes.add("nr_djbt");
        titleTypes.add("fj_bt");
        titleTypes.add("fj_djbt");
        return titleTypes;
    }
}
